{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tic Tac Toe - Kaggle Environment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tictactoe 1.0.0\n",
      "Default Agents:  random reaction\n"
     ]
    }
   ],
   "source": [
    "from kaggle_environments import make\n",
    "env = make(\"tictactoe\")\n",
    "print(env.name, env.version)\n",
    "print(\"Default Agents: \", *env.agents)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TLDR;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<iframe srcdoc=\"<!--\n",
       "  Copyright 2020 Kaggle Inc\n",
       "\n",
       "  Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
       "  you may not use this file except in compliance with the License.\n",
       "  You may obtain a copy of the License at\n",
       "\n",
       "      http://www.apache.org/licenses/LICENSE-2.0\n",
       "\n",
       "  Unless required by applicable law or agreed to in writing, software\n",
       "  distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
       "  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
       "  See the License for the specific language governing permissions and\n",
       "  limitations under the License.\n",
       "-->\n",
       "<!DOCTYPE html>\n",
       "<html lang=&quot;en&quot;>\n",
       "  <head>\n",
       "    <title>Kaggle Simulation Player</title>\n",
       "    <meta name=&quot;viewport&quot; content=&quot;width=device-width,initial-scale=1&quot; />\n",
       "    <link\n",
       "      rel=&quot;stylesheet&quot;\n",
       "      href=&quot;https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css&quot;\n",
       "      crossorigin=&quot;anonymous&quot;\n",
       "    />\n",
       "    <style type=&quot;text/css&quot;>\n",
       "      html,\n",
       "      body {\n",
       "        height: 100%;\n",
       "        font-family: sans-serif;\n",
       "      }\n",
       "      canvas {\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        /* image-rendering: -moz-crisp-edges;\n",
       "        image-rendering: -webkit-crisp-edges;\n",
       "        image-rendering: pixelated;\n",
       "        image-rendering: crisp-edges; */\n",
       "      }\n",
       "    </style>\n",
       "    <script src=&quot;https://unpkg.com/preact@10.0.1/dist/preact.umd.js&quot;></script>\n",
       "    <script src=&quot;https://unpkg.com/preact@10.0.1/hooks/dist/hooks.umd.js&quot;></script>\n",
       "    <script src=&quot;https://unpkg.com/htm@2.2.1/dist/htm.umd.js&quot;></script>\n",
       "    <script>\n",
       "      // Polyfill for Styled Components\n",
       "      window.React = {\n",
       "        ...preact,\n",
       "        createElement: preact.h,\n",
       "        PropTypes: { func: {} },\n",
       "      };\n",
       "    </script>\n",
       "    <script src=&quot;https://unpkg.com/styled-components@3.5.0-0/dist/styled-components.min.js&quot;></script>\n",
       "    <link rel=&quot;canonical&quot; href=&quot;someurl&quot; />\n",
       "  </head>\n",
       "  <body>\n",
       "    <script>\n",
       "      \n",
       "window.kaggle = {\n",
       "  &quot;debug&quot;: true,\n",
       "  &quot;autoplay&quot;: true,\n",
       "  &quot;step&quot;: 0,\n",
       "  &quot;controls&quot;: true,\n",
       "  &quot;environment&quot;: {\n",
       "    &quot;name&quot;: &quot;tictactoe&quot;,\n",
       "    &quot;title&quot;: &quot;Tic Tac Toe&quot;,\n",
       "    &quot;description&quot;: &quot;Classic Tic Tac Toe&quot;,\n",
       "    &quot;version&quot;: &quot;1.0.0&quot;,\n",
       "    &quot;configuration&quot;: {\n",
       "      &quot;steps&quot;: 10,\n",
       "      &quot;timeout&quot;: 2\n",
       "    },\n",
       "    &quot;specification&quot;: {\n",
       "      &quot;action&quot;: {\n",
       "        &quot;description&quot;: &quot;Position to place a mark on the board.&quot;,\n",
       "        &quot;type&quot;: &quot;integer&quot;,\n",
       "        &quot;minimum&quot;: 0,\n",
       "        &quot;maximum&quot;: 8,\n",
       "        &quot;default&quot;: 0\n",
       "      },\n",
       "      &quot;agents&quot;: [\n",
       "        2\n",
       "      ],\n",
       "      &quot;configuration&quot;: {\n",
       "        &quot;steps&quot;: {\n",
       "          &quot;description&quot;: &quot;Maximum number of steps the environment can run.&quot;,\n",
       "          &quot;type&quot;: &quot;integer&quot;,\n",
       "          &quot;minimum&quot;: 10,\n",
       "          &quot;default&quot;: 10\n",
       "        },\n",
       "        &quot;timeout&quot;: {\n",
       "          &quot;description&quot;: &quot;Seconds an agent can run before timing out.&quot;,\n",
       "          &quot;type&quot;: &quot;integer&quot;,\n",
       "          &quot;minimum&quot;: 1,\n",
       "          &quot;default&quot;: 2\n",
       "        }\n",
       "      },\n",
       "      &quot;info&quot;: {},\n",
       "      &quot;observation&quot;: {\n",
       "        &quot;board&quot;: {\n",
       "          &quot;description&quot;: &quot;Serialized 3x3 grid. 0 = Empty, 1 = X, 2 = O&quot;,\n",
       "          &quot;type&quot;: &quot;array&quot;,\n",
       "          &quot;default&quot;: [\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0,\n",
       "            0\n",
       "          ],\n",
       "          &quot;minItems&quot;: 9,\n",
       "          &quot;maxItems&quot;: 9\n",
       "        },\n",
       "        &quot;mark&quot;: {\n",
       "          &quot;description&quot;: &quot;Mark for the agent to use&quot;,\n",
       "          &quot;enum&quot;: [\n",
       "            1,\n",
       "            2\n",
       "          ]\n",
       "        }\n",
       "      },\n",
       "      &quot;reward&quot;: {\n",
       "        &quot;description&quot;: &quot;0 = Lost, 0.5 = Draw, 1 = Won&quot;,\n",
       "        &quot;enum&quot;: [\n",
       "          0,\n",
       "          0.5,\n",
       "          1\n",
       "        ],\n",
       "        &quot;default&quot;: 0.5,\n",
       "        &quot;type&quot;: [\n",
       "          &quot;number&quot;,\n",
       "          &quot;null&quot;\n",
       "        ]\n",
       "      },\n",
       "      &quot;reset&quot;: {\n",
       "        &quot;status&quot;: [\n",
       "          &quot;ACTIVE&quot;,\n",
       "          &quot;INACTIVE&quot;\n",
       "        ],\n",
       "        &quot;observation&quot;: [\n",
       "          {\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          {\n",
       "            &quot;mark&quot;: 2\n",
       "          }\n",
       "        ],\n",
       "        &quot;reward&quot;: 0.5\n",
       "      }\n",
       "    },\n",
       "    &quot;steps&quot;: [\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 4,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 7,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              0,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 3,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 2,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              0\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              2\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;ACTIVE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 8,\n",
       "          &quot;reward&quot;: 0.5,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              0,\n",
       "              2,\n",
       "              2\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;INACTIVE&quot;\n",
       "        }\n",
       "      ],\n",
       "      [\n",
       "        {\n",
       "          &quot;action&quot;: 6,\n",
       "          &quot;reward&quot;: 1,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              2\n",
       "            ],\n",
       "            &quot;mark&quot;: 1\n",
       "          },\n",
       "          &quot;status&quot;: &quot;DONE&quot;\n",
       "        },\n",
       "        {\n",
       "          &quot;action&quot;: 0,\n",
       "          &quot;reward&quot;: 0,\n",
       "          &quot;info&quot;: {},\n",
       "          &quot;observation&quot;: {\n",
       "            &quot;board&quot;: [\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              1,\n",
       "              0,\n",
       "              1,\n",
       "              2,\n",
       "              2\n",
       "            ],\n",
       "            &quot;mark&quot;: 2\n",
       "          },\n",
       "          &quot;status&quot;: &quot;DONE&quot;\n",
       "        }\n",
       "      ]\n",
       "    ],\n",
       "    &quot;rewards&quot;: [\n",
       "      1,\n",
       "      0\n",
       "    ],\n",
       "    &quot;statuses&quot;: [\n",
       "      &quot;DONE&quot;,\n",
       "      &quot;DONE&quot;\n",
       "    ],\n",
       "    &quot;schema_version&quot;: 1\n",
       "  },\n",
       "  &quot;mode&quot;: &quot;ipython&quot;\n",
       "};\n",
       "\n",
       "\n",
       "window.kaggle.renderer = // Copyright 2020 Kaggle Inc\n",
       "//\n",
       "// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\n",
       "// you may not use this file except in compliance with the License.\n",
       "// You may obtain a copy of the License at\n",
       "//\n",
       "//      http://www.apache.org/licenses/LICENSE-2.0\n",
       "//\n",
       "// Unless required by applicable law or agreed to in writing, software\n",
       "// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n",
       "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
       "// See the License for the specific language governing permissions and\n",
       "// limitations under the License.\n",
       "\n",
       "function renderer({\n",
       "  parent,\n",
       "  step,\n",
       "  frame,\n",
       "  environment,\n",
       "  width = 400,\n",
       "  height = 400,\n",
       "}) {\n",
       "  // Canvas Setup.\n",
       "  let canvas = parent.querySelector(&quot;canvas&quot;);\n",
       "  if (!canvas) {\n",
       "    canvas = document.createElement(&quot;canvas&quot;);\n",
       "    parent.appendChild(canvas);\n",
       "\n",
       "    canvas.addEventListener(&quot;click&quot;, () => {\n",
       "      console.log(&quot;canvas click&quot;);\n",
       "    });\n",
       "  }\n",
       "\n",
       "  // Common Dimensions.\n",
       "  const canvasSize = Math.min(height, width);\n",
       "  const unit = 8;\n",
       "  const offset = canvasSize > 400 ? canvasSize * 0.1 : unit / 2;\n",
       "  const cellSize = (canvasSize - offset * 2) / 3;\n",
       "\n",
       "  // Canvas setup and reset.\n",
       "  const c = canvas.getContext(&quot;2d&quot;);\n",
       "  canvas.width = canvasSize;\n",
       "  canvas.height = canvasSize;\n",
       "  c.clearRect(0, 0, canvas.width, canvas.height);\n",
       "\n",
       "  const drawStyle = ({\n",
       "    lineWidth = 1,\n",
       "    lineCap,\n",
       "    strokeStyle = &quot;#FFF&quot;,\n",
       "    shadow,\n",
       "  }) => {\n",
       "    c.lineWidth = lineWidth;\n",
       "    c.strokeStyle = strokeStyle;\n",
       "    if (lineCap) c.lineCap = lineCap;\n",
       "    if (shadow) {\n",
       "      c.shadowOffsetX = shadow.offsetX || 0;\n",
       "      c.shadowOffsetY = shadow.offsetY || 0;\n",
       "      c.shadowColor = shadow.color || strokeStyle;\n",
       "      c.shadowBlur = shadow.blur || 0;\n",
       "    }\n",
       "  };\n",
       "\n",
       "  const drawLine = ({ x1, y1, x2, y2, style }) => {\n",
       "    c.beginPath();\n",
       "    drawStyle(style || {});\n",
       "    c.moveTo((x1 || 0) + offset, (y1 || 0) + offset);\n",
       "    c.lineTo((x2 || x1) + offset, (y2 || y1) + offset);\n",
       "    c.stroke();\n",
       "  };\n",
       "\n",
       "  const drawArc = ({ x, y, radius, sAngle, eAngle, style }) => {\n",
       "    drawStyle(style || {});\n",
       "    c.beginPath();\n",
       "    c.arc(x, y, radius, sAngle, eAngle);\n",
       "    c.stroke();\n",
       "  };\n",
       "\n",
       "  // Draw the Grid.\n",
       "  const gridFrame = step === 0 ? frame : 1;\n",
       "  const drawGridLine = ({\n",
       "    x1s = 0,\n",
       "    y1s = 0,\n",
       "    x2s,\n",
       "    y2s,\n",
       "    x1o = 0,\n",
       "    x2o = 0,\n",
       "    y1o = 0,\n",
       "    y2o = 0,\n",
       "  }) =>\n",
       "    drawLine({\n",
       "      x1: x1s * cellSize + x1o * unit,\n",
       "      x2: (x2s || x1s) * cellSize + x2o * unit,\n",
       "      y1: y1s * cellSize + y1o * unit,\n",
       "      y2: (y2s || y1s) * cellSize + y2o * unit,\n",
       "      style: { strokeStyle: &quot;#046BBF&quot; },\n",
       "    });\n",
       "\n",
       "  // Vertical.\n",
       "  drawGridLine({ x1s: 1, y1s: 0, y2s: gridFrame, y2o: -1 });\n",
       "  drawGridLine({ x1s: 2, y1s: 0, y2s: gridFrame, y2o: -1 });\n",
       "  drawGridLine({ x1s: 1, y1s: 1, y2s: 1 + gridFrame, y1o: 1, y2o: -1 });\n",
       "  drawGridLine({ x1s: 2, y1s: 1, y2s: 1 + gridFrame, y1o: 1, y2o: -1 });\n",
       "  drawGridLine({ x1s: 1, y1s: 2, y2s: 2 + gridFrame, y1o: 1 });\n",
       "  drawGridLine({ x1s: 2, y1s: 2, y2s: 2 + gridFrame, y1o: 1 });\n",
       "\n",
       "  // Horizontal.\n",
       "  drawGridLine({ x1s: 0, y1s: 1, x2s: gridFrame, x2o: -1 });\n",
       "  drawGridLine({ x1s: 1, y1s: 1, x2s: 1 + gridFrame, x1o: 1, x2o: -1 });\n",
       "  drawGridLine({ x1s: 2, y1s: 1, x2s: 2 + gridFrame, x1o: 1 });\n",
       "  drawGridLine({ x1s: 0, y1s: 2, x2s: gridFrame, x2o: -1 });\n",
       "  drawGridLine({ x1s: 1, y1s: 2, x2s: 1 + gridFrame, x1o: 1, x2o: -1 });\n",
       "  drawGridLine({ x1s: 2, y1s: 2, x2s: 2 + gridFrame, x1o: 1 });\n",
       "\n",
       "  // Draw the Pieces.\n",
       "  const drawX = (cell, cellFrame) => {\n",
       "    const part = cellSize / 4;\n",
       "    const gap = Math.min(Math.sqrt((unit * unit) / 2), canvasSize / 50);\n",
       "    const row = Math.floor(cell / 3);\n",
       "    const col = cell % 3;\n",
       "\n",
       "    const drawXLine = ({ x1, y1, x2, y2 }) =>\n",
       "      drawLine({\n",
       "        x1: col * cellSize + x1,\n",
       "        y1: row * cellSize + y1,\n",
       "        x2: col * cellSize + x2,\n",
       "        y2: row * cellSize + y2,\n",
       "        style: {\n",
       "          strokeStyle: &quot;#00FFFF&quot;,\n",
       "          lineWidth: 2,\n",
       "          lineCap: &quot;round&quot;,\n",
       "          shadow: { blur: 8 },\n",
       "        },\n",
       "      });\n",
       "\n",
       "    drawXLine({\n",
       "      x1: part,\n",
       "      y1: part,\n",
       "      x2: part + part * 2 * cellFrame,\n",
       "      y2: part + part * 2 * cellFrame,\n",
       "    });\n",
       "    if (Math.round(cellFrame) === 1) {\n",
       "      drawXLine({\n",
       "        x1: part,\n",
       "        y1: part * 3,\n",
       "        x2: part * 2 - gap,\n",
       "        y2: part * 2 + gap,\n",
       "      });\n",
       "      drawXLine({\n",
       "        x1: part * 2 + gap,\n",
       "        y1: part * 2 - gap,\n",
       "        x2: part * 3,\n",
       "        y2: part,\n",
       "      });\n",
       "    }\n",
       "  };\n",
       "  const drawO = (cell, cellFrame) => {\n",
       "    const row = Math.floor(cell / 3);\n",
       "    const col = cell % 3;\n",
       "    const radius = cellSize / 4 + 1; // +1 is for optical illusion.\n",
       "    const gap =\n",
       "      (Math.acos((2 * (radius ^ 2) - (unit ^ 2)) / (2 * radius * radius)) /\n",
       "        180) *\n",
       "      Math.PI *\n",
       "      unit;\n",
       "    const x = cellSize * col + cellSize / 2 + offset;\n",
       "    const y = cellSize * row + cellSize / 2 + offset;\n",
       "\n",
       "    const drawOArc = (sAngle, eAngle) =>\n",
       "      drawArc({\n",
       "        x,\n",
       "        y,\n",
       "        radius,\n",
       "        sAngle,\n",
       "        eAngle,\n",
       "        style: {\n",
       "          lineWidth: 2,\n",
       "          strokeStyle: &quot;#FFF&quot;,\n",
       "          shadow: { blur: 8 },\n",
       "        },\n",
       "      });\n",
       "\n",
       "    drawOArc(\n",
       "      -Math.PI / 2 + gap,\n",
       "      -Math.PI / 2 + gap + (Math.PI - gap * 2) * cellFrame\n",
       "    );\n",
       "    drawOArc(\n",
       "      Math.PI / 2 + gap,\n",
       "      Math.PI / 2 + gap + (Math.PI - gap * 2) * cellFrame\n",
       "    );\n",
       "  };\n",
       "\n",
       "  const board = environment.steps[step][0].observation.board;\n",
       "\n",
       "  board.forEach((value, cell) => {\n",
       "    const cellFrame =\n",
       "      step <= 1 ||\n",
       "      environment.steps[step - 1][0].observation.board[cell] !== value\n",
       "        ? frame\n",
       "        : 1;\n",
       "    if (value === 1) drawX(cell, cellFrame);\n",
       "    if (value === 2) drawO(cell, cellFrame);\n",
       "  });\n",
       "\n",
       "  // Draw the winning line.\n",
       "  // [cell1, cell2, cell3, x1, y1, x2, y2]\n",
       "  const checks = [\n",
       "    [0, 1, 2, 1 / 19, 1 / 6, 18 / 19, 1 / 6],\n",
       "    [3, 4, 5, 1 / 19, 1 / 2, 18 / 19, 1 / 2],\n",
       "    [6, 7, 8, 1 / 19, 5 / 6, 18 / 19, 5 / 6],\n",
       "    [0, 3, 6, 1 / 6, 1 / 19, 1 / 6, 18 / 19],\n",
       "    [1, 4, 7, 1 / 2, 1 / 19, 1 / 2, 18 / 19],\n",
       "    [2, 5, 8, 5 / 6, 1 / 19, 5 / 6, 18 / 19],\n",
       "    [0, 4, 8, 1 / 19, 1 / 19, 18 / 19, 18 / 19],\n",
       "    [2, 4, 6, 18 / 19, 1 / 19, 1 / 19, 18 / 19],\n",
       "  ];\n",
       "  for (const check of checks) {\n",
       "    if (\n",
       "      board[check[0]] !== 0 &&\n",
       "      board[check[0]] === board[check[1]] &&\n",
       "      board[check[0]] === board[check[2]]\n",
       "    ) {\n",
       "      const x1 = check[3] * (cellSize * 3);\n",
       "      const y1 = check[4] * (cellSize * 3);\n",
       "      const winFrame = frame < 0.5 ? 0 : (frame - 0.5) / 0.5;\n",
       "      if (winFrame > 0) {\n",
       "        drawLine({\n",
       "          x1,\n",
       "          y1,\n",
       "          x2: x1 + (check[5] * (cellSize * 3) - x1) * winFrame,\n",
       "          y2: y1 + (check[6] * (cellSize * 3) - y1) * winFrame,\n",
       "          style: {\n",
       "            strokeStyle: &quot;#FFF&quot;,\n",
       "            lineWidth: 3 * winFrame,\n",
       "            shadow: { blur: 8 * winFrame },\n",
       "          },\n",
       "        });\n",
       "      }\n",
       "      break;\n",
       "    }\n",
       "  }\n",
       "};\n",
       "\n",
       "\n",
       "    \n",
       "    </script>\n",
       "    <script>\n",
       "      const h = htm.bind(preact.h);\n",
       "      const { useContext, useEffect, useRef, useState } = preactHooks;\n",
       "      const styled = window.styled.default;\n",
       "\n",
       "      const Context = preact.createContext({});\n",
       "\n",
       "      const Loading = styled.div`\n",
       "        animation: rotate360 1.1s infinite linear;\n",
       "        border: 8px solid rgba(255, 255, 255, 0.2);\n",
       "        border-left-color: #0cb1ed;\n",
       "        border-radius: 50%;\n",
       "        height: 40px;\n",
       "        position: relative;\n",
       "        transform: translateZ(0);\n",
       "        width: 40px;\n",
       "\n",
       "        @keyframes rotate360 {\n",
       "          0% {\n",
       "            transform: rotate(0deg);\n",
       "          }\n",
       "          100% {\n",
       "            transform: rotate(360deg);\n",
       "          }\n",
       "        }\n",
       "      `;\n",
       "\n",
       "      const Logo = styled(\n",
       "        props => h`\n",
       "        <a href=&quot;https://kaggle.com&quot; target=&quot;_blank&quot; className=${props.className}>\n",
       "          <svg width=&quot;62px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 62 24&quot; version=&quot;1.1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;>\n",
       "            <g fill=&quot;#1EBEFF&quot; fill-rule=&quot;nonzero&quot;>\n",
       "              <path d=&quot;M10.2,17.8c0,0.1-0.1,0.1-0.2,0.1H7.7c-0.1,0-0.3-0.1-0.4-0.2l-3.8-4.9l-1.1,1v3.8 c0,0.2-0.1,0.3-0.3,0.3H0.3c-0.2,0-0.3-0.1-0.3-0.3V0.3C0.1,0.1,0.2,0,0.3,0h1.8c0.2,0,0.3,0.1,0.3,0.3V11L7,6.3 c0.1-0.1,0.2-0.2,0.4-0.2h2.4c0.1,0,0.2,0,0.2,0.1c0,0.1,0,0.2,0,0.2l-4.9,4.7l5.1,6.3C10.2,17.6,10.2,17.7,10.2,17.8z&quot;/>\n",
       "              <path d=&quot;M19.6,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3v-0.4c-0.8,0.6-1.8,0.9-3,0.9c-1.1,0-2-0.3-2.8-1 c-0.8-0.7-1.2-1.6-1.2-2.7c0-1.7,1.1-2.9,3.2-3.5c0.8-0.2,2.1-0.5,3.8-0.6c0.1-0.6-0.1-1.2-0.5-1.7c-0.4-0.5-1-0.7-1.7-0.7 c-1,0-2,0.4-3,1C12.2,9.1,12.1,9.1,12,9l-0.9-1.3C11,7.5,11,7.4,11.1,7.3c1.3-0.9,2.7-1.4,4.2-1.4c1.1,0,2.1,0.3,2.8,0.8 c1.1,0.8,1.7,2,1.7,3.7v7.3C19.9,17.8,19.8,17.9,19.6,17.9z M17.5,12.4c-1.7,0.2-2.9,0.4-3.5,0.7c-0.9,0.4-1.2,0.9-1.1,1.6 c0.1,0.4,0.2,0.7,0.6,0.9c0.3,0.2,0.7,0.4,1.1,0.4c1.2,0.1,2.2-0.2,2.9-1V12.4z&quot;/>\n",
       "              <path d=&quot;M30.6,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3v11.7C32,20,31.5,21.5,30.6,22.5z M29.7,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7V9.9z&quot;/>\n",
       "              <path d=&quot;M42.9,22.5c-0.9,1-2.3,1.5-4,1.5c-1,0-2-0.3-2.9-0.8c-0.2-0.1-0.4-0.3-0.7-0.5 c-0.3-0.2-0.6-0.5-0.9-0.7c-0.1-0.1-0.1-0.2,0-0.4l1.2-1.2c0.1-0.1,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1c1,1,1.9,1.5,2.8,1.5 c2.1,0,3.2-1.1,3.2-3.3v-1.4c-0.8,0.7-1.9,1-3.3,1c-1.7,0-3-0.6-4-1.9c-0.8-1.1-1.3-2.5-1.3-4.2c0-1.6,0.4-3,1.2-4.1 c0.9-1.3,2.3-2,4-2c1.3,0,2.4,0.3,3.3,1V6.4c0-0.2,0.1-0.3,0.3-0.3H44c0.2,0,0.3,0.1,0.3,0.3v11.7C44.3,20,43.8,21.5,42.9,22.5z M42,9.9c-0.4-1.1-1.4-1.7-3-1.7c-2,0-3.1,1.3-3.1,3.8c0,1.4,0.3,2.4,1,3.1c0.5,0.5,1.2,0.8,2,0.8c1.6,0,2.7-0.6,3.1-1.7L42,9.9 L42,9.9z&quot;/>\n",
       "              <path d=&quot;M48.3,17.9h-1.8c-0.2,0-0.3-0.1-0.3-0.3V0.3c0-0.2,0.1-0.3,0.3-0.3h1.8c0.2,0,0.3,0.1,0.3,0.3 v17.3C48.5,17.8,48.5,17.9,48.3,17.9z&quot;/>\n",
       "              <path d=&quot;M61.4,12.6c0,0.2-0.1,0.3-0.3,0.3h-8.5c0.1,0.9,0.5,1.6,1.1,2.2c0.7,0.6,1.6,0.9,2.7,0.9 c1,0,1.8-0.3,2.6-0.8c0.2-0.1,0.3-0.1,0.4,0l1.2,1.3c0.1,0.1,0.1,0.3,0,0.4c-1.3,0.9-2.7,1.4-4.4,1.4c-1.8,0-3.3-0.6-4.4-1.8 c-1.1-1.2-1.7-2.7-1.7-4.5c0-1.7,0.6-3.2,1.7-4.4c1-1.1,2.4-1.6,4.1-1.6c1.6,0,2.9,0.6,4,1.7c1.1,1.2,1.6,2.6,1.5,4.4L61.4,12.6 z M58,8.7c-0.6-0.5-1.3-0.8-2.1-0.8c-0.8,0-1.5,0.3-2.1,0.8c-0.6,0.5-1,1.2-1.1,2H59C59,9.9,58.6,9.3,58,8.7z&quot;/>\n",
       "            </g>\n",
       "          </svg>\n",
       "        </a>\n",
       "      `\n",
       "      )`\n",
       "        display: inline-flex;\n",
       "      `;\n",
       "\n",
       "      const Header = styled(props => {\n",
       "        const { environment } = useContext(Context);\n",
       "\n",
       "        return h`<div className=${props.className} >\n",
       "          <${Logo} />\n",
       "          ${environment.title}\n",
       "        </div>`;\n",
       "      })`\n",
       "        align-items: center;\n",
       "        border-bottom: 4px solid #212121;\n",
       "        box-sizing: border-box;\n",
       "        color: #fff;\n",
       "        display: flex;\n",
       "        flex: 0 0 36px;\n",
       "        font-size: 14px;\n",
       "        justify-content: space-between;\n",
       "        padding: 0 8px;\n",
       "        width: 100%;\n",
       "      `;\n",
       "\n",
       "      const Viewer = styled(props => {\n",
       "        const {\n",
       "          animate,\n",
       "          debug,\n",
       "          playing,\n",
       "          renderer,\n",
       "          step,\n",
       "          speed,\n",
       "          environment,\n",
       "        } = useContext(Context);\n",
       "        const ref = preact.createRef();\n",
       "        const stepRef = useRef(-1);\n",
       "        stepRef.current = step;\n",
       "\n",
       "        useEffect(async () => {\n",
       "          if (!ref.current) return;\n",
       "\n",
       "          const renderFrame = async (start, startStep, lastFrame) => {\n",
       "            if (startStep !== stepRef.current) return;\n",
       "            if (lastFrame === 1) {\n",
       "              if (!animate) return;\n",
       "              start = Date.now();\n",
       "            }\n",
       "            const frame =\n",
       "              playing || animate\n",
       "                ? Math.min((Date.now() - start) / speed, 1)\n",
       "                : 1;\n",
       "            try {\n",
       "              if (debug) console.time(&quot;render&quot;);\n",
       "              await renderer({\n",
       "                parent: ref.current,\n",
       "                environment,\n",
       "                step,\n",
       "                frame,\n",
       "                width: ref.current.clientWidth,\n",
       "                height: ref.current.clientHeight,\n",
       "                styled,\n",
       "                preact,\n",
       "                hooks: preactHooks,\n",
       "              });\n",
       "            } catch (e) {\n",
       "              console.log(\n",
       "                &quot;Frame:&quot;,\n",
       "                frame,\n",
       "                &quot;Step:&quot;,\n",
       "                step,\n",
       "                &quot;Environment:&quot;,\n",
       "                environment,\n",
       "                &quot;Error:&quot;,\n",
       "                e\n",
       "              );\n",
       "            } finally {\n",
       "              if (debug) console.timeEnd(&quot;render&quot;);\n",
       "            }\n",
       "            window.requestAnimationFrame(() =>\n",
       "              renderFrame(start, startStep, frame)\n",
       "            );\n",
       "          };\n",
       "\n",
       "          await renderFrame(Date.now(), stepRef.current);\n",
       "        }, [ref.current, step]);\n",
       "\n",
       "        return h`<div className=${props.className} ref=${ref} />`;\n",
       "      })`\n",
       "        align-items: center;\n",
       "        background-color: #000b2a;\n",
       "        background-image: radial-gradient(\n",
       "          circle closest-side,\n",
       "          #000b49,\n",
       "          #000b2a\n",
       "        );\n",
       "        box-sizing: border-box;\n",
       "        display: flex;\n",
       "        flex: 1;\n",
       "        justify-content: center;\n",
       "        overflow: auto;\n",
       "        position: relative;\n",
       "        width: 100%;\n",
       "      `;\n",
       "\n",
       "      const StepInput = styled.input.attrs({\n",
       "        type: &quot;range&quot;,\n",
       "      })`\n",
       "        appearance: none;\n",
       "        background: rgba(255, 255, 255, 0.15);\n",
       "        border-radius: 2px;\n",
       "        display: block;\n",
       "        flex: 1;\n",
       "        height: 4px;\n",
       "        opacity: 0.8;\n",
       "        outline: none;\n",
       "        transition: opacity 0.2s;\n",
       "        width: 100%;\n",
       "\n",
       "        &:hover {\n",
       "          opacity: 1;\n",
       "        }\n",
       "\n",
       "        &::-webkit-slider-thumb {\n",
       "          appearance: none;\n",
       "          background: #1ebeff;\n",
       "          border-radius: 100%;\n",
       "          cursor: pointer;\n",
       "          height: 12px;\n",
       "          margin: 0;\n",
       "          position: relative;\n",
       "          width: 12px;\n",
       "\n",
       "          &::after {\n",
       "            content: &quot;hello&quot;;\n",
       "            position: absolute;\n",
       "            top: 0px;\n",
       "            left: 0px;\n",
       "            width: 200px;\n",
       "            height: 8px;\n",
       "            background: green;\n",
       "          }\n",
       "        }\n",
       "      `;\n",
       "\n",
       "      const PlayButton = styled.button`\n",
       "        align-items: center;\n",
       "        background: none;\n",
       "        border: none;\n",
       "        color: white;\n",
       "        cursor: pointer;\n",
       "        display: flex;\n",
       "        flex: 0 0 56px;\n",
       "        font-size: 20px;\n",
       "        height: 40px;\n",
       "        justify-content: center;\n",
       "        opacity: 0.8;\n",
       "        outline: none;\n",
       "        transition: opacity 0.2s;\n",
       "\n",
       "        &:hover {\n",
       "          opacity: 1;\n",
       "        }\n",
       "      `;\n",
       "\n",
       "      const StepCount = styled.span`\n",
       "        align-items: center;\n",
       "        color: white;\n",
       "        display: flex;\n",
       "        font-size: 14px;\n",
       "        justify-content: center;\n",
       "        opacity: 0.8;\n",
       "        padding: 0 16px;\n",
       "        pointer-events: none;\n",
       "      `;\n",
       "\n",
       "      const Controls = styled(props => {\n",
       "        const { environment, pause, play, playing, setStep, step } = useContext(\n",
       "          Context\n",
       "        );\n",
       "        const value = step + 1;\n",
       "        const onClick = () => (playing ? pause() : play());\n",
       "        const onInput = e => {\n",
       "          pause();\n",
       "          setStep(parseInt(e.target.value) - 1);\n",
       "        };\n",
       "\n",
       "        return h`\n",
       "          <div className=${props.className}>\n",
       "            <${PlayButton} onClick=${onClick}><svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24px&quot; height=&quot;24px&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;#FFFFFF&quot;>${\n",
       "          playing\n",
       "            ? h`<path d=&quot;M6 19h4V5H6v14zm8-14v14h4V5h-4z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
       "            : h`<path d=&quot;M8 5v14l11-7z&quot;/><path d=&quot;M0 0h24v24H0z&quot; fill=&quot;none&quot;/>`\n",
       "        }</svg><//>\n",
       "            <${StepInput} min=&quot;1&quot; max=${\n",
       "          environment.steps.length\n",
       "        } value=&quot;${value}&quot; onInput=${onInput} />\n",
       "            <${StepCount}>${value} / ${environment.steps.length}<//>\n",
       "          </div>\n",
       "        `;\n",
       "      })`\n",
       "        align-items: center;\n",
       "        border-top: 4px solid #212121;\n",
       "        display: flex;\n",
       "        flex: 0 0 44px;\n",
       "        width: 100%;\n",
       "      `;\n",
       "\n",
       "      const Info = styled(props => {\n",
       "        const {\n",
       "          environment,\n",
       "          playing,\n",
       "          step,\n",
       "          speed,\n",
       "          animate,\n",
       "          header,\n",
       "          controls,\n",
       "          settings,\n",
       "        } = useContext(Context);\n",
       "\n",
       "        return h`\n",
       "          <div className=${props.className}>\n",
       "            info:\n",
       "            step(${step}),\n",
       "            playing(${playing ? &quot;T&quot; : &quot;F&quot;}),\n",
       "            speed(${speed}),\n",
       "            animate(${animate ? &quot;T&quot; : &quot;F&quot;})\n",
       "          </div>`;\n",
       "      })`\n",
       "        color: #888;\n",
       "        font-family: monospace;\n",
       "        font-size: 12px;\n",
       "      `;\n",
       "\n",
       "      const Settings = styled(props => {\n",
       "        const { environment, pause, play, playing, setStep, step } = useContext(\n",
       "          Context\n",
       "        );\n",
       "\n",
       "        return h`\n",
       "          <div className=${props.className}>\n",
       "            <${Info} />\n",
       "          </div>\n",
       "        `;\n",
       "      })`\n",
       "        background: #fff;\n",
       "        border-top: 4px solid #212121;\n",
       "        box-sizing: border-box;\n",
       "        padding: 20px;\n",
       "        width: 100%;\n",
       "\n",
       "        h1 {\n",
       "          font-size: 20px;\n",
       "        }\n",
       "      `;\n",
       "\n",
       "      const Player = styled(props => {\n",
       "        const context = useContext(Context);\n",
       "        const { controls, header, loading, settings } = context;\n",
       "        return h`\n",
       "          <div className=${props.className}>\n",
       "            ${loading && h`<${Loading} />`}\n",
       "            ${!loading && header && h`<${Header} />`}\n",
       "            ${!loading && h`<${Viewer} />`}\n",
       "            ${!loading && controls && h`<${Controls} />`}\n",
       "            ${!loading && settings && h`<${Settings} />`}\n",
       "          </div>`;\n",
       "      })`\n",
       "        align-items: center;\n",
       "        background: #212121;\n",
       "        border: 4px solid #212121;\n",
       "        box-sizing: border-box;\n",
       "        display: flex;\n",
       "        flex-direction: column;\n",
       "        height: 100%;\n",
       "        justify-content: center;\n",
       "        position: relative;\n",
       "        width: 100%;\n",
       "      `;\n",
       "\n",
       "      const App = () => {\n",
       "        const renderCountRef = useRef(0);\n",
       "        const [_, setRenderCount] = useState(0);\n",
       "\n",
       "        const contextRef = useRef({\n",
       "          animate: false,\n",
       "          autoplay: false,\n",
       "          controls: false,\n",
       "          debug: false,\n",
       "          header: window.innerHeight >= 600,\n",
       "          loading: false,\n",
       "          environment: { steps: [] },\n",
       "          playing: false,\n",
       "          renderer: () => &quot;DNE&quot;,\n",
       "          settings: false,\n",
       "          speed: 500,\n",
       "          step: 0,\n",
       "        });\n",
       "\n",
       "        // Context helpers.\n",
       "        const rerender = (contextRef.current.rerender = () =>\n",
       "          setRenderCount((renderCountRef.current += 1)));\n",
       "        const setStep = (contextRef.current.setStep = newStep => {\n",
       "          contextRef.current.step = newStep;\n",
       "          rerender();\n",
       "        });\n",
       "        const setPlaying = (contextRef.current.setPlaying = playing => {\n",
       "          contextRef.current.playing = playing;\n",
       "          rerender();\n",
       "        });\n",
       "        const pause = (contextRef.current.pause = () => setPlaying(false));\n",
       "\n",
       "        const playNext = () => {\n",
       "          const context = contextRef.current;\n",
       "\n",
       "          if (\n",
       "            context.playing &&\n",
       "            context.step < context.environment.steps.length - 1\n",
       "          ) {\n",
       "            setStep(context.step + 1);\n",
       "            play(true);\n",
       "          } else {\n",
       "            pause();\n",
       "          }\n",
       "        };\n",
       "\n",
       "        const play = (contextRef.current.play = continuing => {\n",
       "          const context = contextRef.current;\n",
       "          if (context.playing && !continuing) return;\n",
       "          if (!context.playing) setPlaying(true);\n",
       "          if (\n",
       "            !continuing &&\n",
       "            context.step === context.environment.steps.length - 1\n",
       "          ) {\n",
       "            setStep(0);\n",
       "          }\n",
       "          setTimeout(playNext, context.speed);\n",
       "        });\n",
       "\n",
       "        const updateContext = o => {\n",
       "          const context = contextRef.current;\n",
       "          Object.assign(context, o, {\n",
       "            environment: { ...context.environment, ...(o.environment || {}) },\n",
       "          });\n",
       "          rerender();\n",
       "\n",
       "          // If autoplay, toggle to playing.\n",
       "          if (context.autoplay) play();\n",
       "        };\n",
       "\n",
       "        // First time setup.\n",
       "        useEffect(() => {\n",
       "          // Timeout is used to ensure useEffect renders once.\n",
       "          setTimeout(() => {\n",
       "            // Initialize context with window.kaggle.\n",
       "            updateContext(window.kaggle || {});\n",
       "            // Listen for messages received to update the context.\n",
       "            window.addEventListener(\n",
       "              &quot;message&quot;,\n",
       "              event => {\n",
       "                // Ensure the environment names match before updating.\n",
       "                try {\n",
       "                  if (\n",
       "                    event.data.environment.name ==\n",
       "                    contextRef.current.environment.name\n",
       "                  ) {\n",
       "                    updateContext(event.data);\n",
       "                  }\n",
       "                } catch {}\n",
       "              },\n",
       "              false\n",
       "            );\n",
       "          }, 1);\n",
       "        }, []);\n",
       "\n",
       "        if (contextRef.current.debug) {\n",
       "          console.log(&quot;context&quot;, contextRef.current);\n",
       "        }\n",
       "\n",
       "        return h`\n",
       "          <${Context.Provider} value=${contextRef.current}>\n",
       "            <${Player} />\n",
       "          <//>`;\n",
       "      };\n",
       "\n",
       "      preact.render(h`<${App} />`, document.body);\n",
       "    </script>\n",
       "  </body>\n",
       "</html>\n",
       "\" width=\"300\" height=\"300\" frameborder=\"0\"></iframe> "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def agent(observation):\n",
    "    board = observation.board\n",
    "    play_order = [4,0,2,6,8,1,3,5,7]\n",
    "    EMPTY = 0\n",
    "    return [c for c in play_order if board[c] == EMPTY][0]\n",
    "\n",
    "env = make(\"tictactoe\", debug=True)\n",
    "\n",
    "# play agent above vs default random agent.\n",
    "env.run([agent, \"random\"])\n",
    "env.render(mode=\"ipython\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Specification"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Observation: {\n",
      "    \"board\": {\n",
      "        \"default\": [\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0,\n",
      "            0\n",
      "        ],\n",
      "        \"description\": \"Serialized 3x3 grid. 0 = Empty, 1 = X, 2 = O\",\n",
      "        \"maxItems\": 9,\n",
      "        \"minItems\": 9,\n",
      "        \"type\": \"array\"\n",
      "    },\n",
      "    \"mark\": {\n",
      "        \"description\": \"Mark for the agent to use\",\n",
      "        \"enum\": [\n",
      "            1,\n",
      "            2\n",
      "        ]\n",
      "    }\n",
      "}\n",
      "Action: {\n",
      "    \"default\": 0,\n",
      "    \"description\": \"Position to place a mark on the board.\",\n",
      "    \"maximum\": 8,\n",
      "    \"minimum\": 0,\n",
      "    \"type\": \"integer\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "print(\"Observation:\", json.dumps(env.specification.observation, indent=4, sort_keys=True))\n",
    "print(\"Action:\", json.dumps(env.specification.action, indent=4, sort_keys=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training using Gym"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " X | X | O \n",
      "---+---+---\n",
      " X | O |   \n",
      "---+---+---\n",
      " O |   |   \n"
     ]
    }
   ],
   "source": [
    "from kaggle_environments import make\n",
    "import gym\n",
    "\n",
    "class TicTacToe(gym.Env):\n",
    "\n",
    "    def __init__(self):\n",
    "        self.env = make(\"tictactoe\", debug=True)\n",
    "        self.trainer = self.env.train([None, \"random\"])\n",
    "        \n",
    "        # Define required gym fields (examples):\n",
    "        self.action_space = gym.spaces.Discrete(9)\n",
    "        self.observation_space = gym.spaces.Discrete(27)\n",
    "\n",
    "    def step(self, action):\n",
    "        return self.trainer.step(action)\n",
    "    \n",
    "    def reset(self):\n",
    "        return self.trainer.reset()\n",
    "    \n",
    "    def render(self, **kwargs):\n",
    "        return self.env.render(**kwargs)\n",
    "        \n",
    "    \n",
    "env = TicTacToe()\n",
    "\n",
    "done = False\n",
    "obs = env.reset()\n",
    "while not done:\n",
    "    # Choose first available empty cell as the action.\n",
    "    action = [i for i in range(len(obs.board)) if obs.board[i] == 0][0]\n",
    "    obs, reward, done, info = env.step(action)\n",
    "env.render()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
